﻿namespace EFS.RC.CC.Presences.Operators
{
	/// <summary>
	/// Presences
	/// </summary>
	internal abstract class Presence: EFS.Common.ISelfDescriptor
	{
		#region Composition

		// sync acces
		private object syncAccess = new object();

		/// <summary>
		/// On-line status
		/// </summary>
		public System.Boolean IsOnline { get; private set; }
		
		/// <summary>
		/// Available for conversation
		/// </summary>
		public virtual System.Boolean IsAvailable { get; private set; }

		/// Available since
		public System.DateTime IsAvailableSince { get; private set; }
		
		#endregion

		#region Delegates

		/// <summary>
		/// Prence status changed delegate
		/// </summary>
		/// <param name="?"></param>
		protected delegate void PresenceAvailabilityChanged(System.Boolean oldAvailability, System.Boolean newAvailability);

		/// Call to presence avail changed events
		protected PresenceAvailabilityChanged OnPresenceAvailabilityChanged = null;

		#endregion

		#region Usage

		/// <summary>
		/// AD User: Get
		/// </summary>
		public abstract EFS.AD.User User
		{
			get;
		}

		/// <summary>
		/// Describe this
		/// </summary>
		/// <returns></returns>
		public virtual System.String Describe()
		{
			return System.String.Format("EFS.RC.CC.Presences.Operators.Presence: {0} Online: {1} Available: {2}", User.SIP, IsOnline, IsAvailable);
		}

		/// <summary>
		/// Update deploymentOperator
		/// </summary>
		/// <param name="notification"></param>
		public void Update(Microsoft.Rtc.Collaboration.Presence.RemotePresentityNotification notification)
		{
			// log
			EFS.EventLog.Log.LogInfo("Update", this);

			// check
			EFS.Common.Verify.Reference(notification, "notification");

			// availability
			System.Int64 availability = notification.AggregatedPresenceState.AvailabilityValue;

			// log
			EFS.RC.CC.Tools.Loggers.CHL.Add(User.ObjectGuid, (System.Int32)availability, GetCustomActivityDescription(notification));

			// loack access
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// check online
				IsOnline = 
					availability >= (System.Int64)Microsoft.Rtc.Collaboration.Presence.PresenceAvailability.Online &&
					availability < (System.Int64)Microsoft.Rtc.Collaboration.Presence.PresenceAvailability.Offline;

				// check availability
				System.Boolean isAvailable =
					availability >= (System.Int64)Microsoft.Rtc.Collaboration.Presence.PresenceAvailability.Online &&
					availability < (System.Int64)Microsoft.Rtc.Collaboration.Presence.PresenceAvailability.Busy;

				// check availability changes
				if (IsAvailable != isAvailable)
				{
					// presence status changed, call event
					if (null != OnPresenceAvailabilityChanged)
					{
						try
						{
							OnPresenceAvailabilityChanged(IsAvailable, isAvailable);
						}
						catch (System.Exception ex)
						{
							// log
							EFS.EventLog.Log.LogException(ex, this);
						}
					}

					// set
					IsAvailable = isAvailable;

					// check 
					if (IsAvailable)
					{
						// since available
						IsAvailableSince = System.DateTime.Now;
					}
					else
					{
						IsAvailableSince = System.DateTime.MaxValue;
					}
				}

				// log status
				EFS.EventLog.Log.LogInfo("Update : New status", this);		
			}
		}

		#endregion

		#region Internals

		/// <summary>
		/// Get customactivity desc from notification
		/// </summary>
		/// <returns></returns>
		private System.String GetCustomActivityDescription(Microsoft.Rtc.Collaboration.Presence.RemotePresentityNotification notification)
		{
			// log
			EFS.EventLog.Log.LogInfo("Update", this);

			// check
			EFS.Common.Verify.Reference(notification, "notification");

			// custom act desc
			System.String customActivityDescription = null;

			try
			{
				Microsoft.Rtc.Collaboration.Presence.PresenceActivity presenceActivity = notification.AggregatedPresenceState.Activity;
				if (null != presenceActivity && null != presenceActivity.CustomTokens && presenceActivity.CustomTokens.Count > 0)
				{
					customActivityDescription = presenceActivity.CustomTokens[0].Value;
				}
			}
			catch (System.Exception ex)
			{
				EFS.EventLog.Log.LogException(ex, this);
			}

			// done
			return customActivityDescription;
		}

		#endregion
	}
}
